package main

import (
	"container/list"
	"fmt"
	"github.com/PuerkitoBio/goquery"
	"github.com/gin-gonic/gin"
	"github.com/goccy/go-json"
	"github.com/gocolly/colly"
	"golang.org/x/net/context"
	"log"
	"net/http"
	"net/url"
	"strings"
	"time"
)

var hostname string

func main() {
	err := initClient()
	if err != nil {
		log.Fatal("redis 初始化失败", err)
	}
	r := gin.Default()
	r.GET("/search", func(c *gin.Context) {
		fuzzy := c.Query("fuzzy")
		fuzzySearch(fuzzy)
		c.JSON(200, gin.H{
			"message": "pong",
		})
	})
	r.Run("[::]:8081")
}

func fuzzySearch(fuzzy string) {
	books := parseList("https://annas-archive.gs/search?q=" + url.PathEscape(fuzzy))

	front := books.Front()
	// save to redis
	for front != nil {
		bytes, err := json.Marshal(front.Value)
		if err != nil {
			fmt.Println(err)
			continue
		}
		// 在列表头部添加元素
		v := string(bytes)
		log.Println("data is insert to redis: ", v)
		redisDb.LPush(context.Background(), "annasList", v)
		front = front.Next()
	}
}

type BookDetail struct {
	Url       string
	ImgUrl    string
	Format    string
	Name      string
	Date      string
	Author    string
	Timestamp int64
}

func parseList(path string) *list.List {
	l := list.New()
	c := colly.NewCollector()
	// 设置代理
	proxyURL, err := url.Parse("http://127.0.0.1:7890")
	if err != nil {
		fmt.Println("Error parsing proxy URL:", err)
		return l
	}

	parse, err := url.Parse(path)
	if err != nil {
		fmt.Println("Error parsing proxy URL:", err)
		return l
	}

	hostname = parse.Hostname()

	// 创建自定义的 http.Client
	client := &http.Client{
		Transport: &http.Transport{
			Proxy: http.ProxyURL(proxyURL),
		},
	}
	c.WithTransport(client.Transport)

	// 在页面中找到所有的链接
	c.OnHTML("main form div.flex.w-full div.mb-4", func(e *colly.HTMLElement) {
		//fmt.Println(e.DOM.Html())
		nodes := e.DOM.Find("div")
		nodes.Each(func(i int, node *goquery.Selection) {
			class, exists := node.Attr("class")
			if !exists || !strings.Contains(class, "h-[125] flex flex-col justify-center") {
				node = node.Next()
				return
			}
			ret, err2 := node.Html()
			if err2 != nil {
				log.Println(err2)
				node = node.Next()
				return
			}
			ret = strings.TrimSpace(ret)
			if strings.HasPrefix(ret, "<!--") && strings.HasSuffix(ret, "-->") {
				ret = strings.Replace(ret, "<!--", "", 1)
				ret = strings.Replace(ret, "-->", "", 1)
				node.SetHtml(ret)
			}
			bookDetail := parseNode(node)
			if bookDetail != nil {
				l.PushBack(bookDetail)
			}
			node = node.Next()
		})
	})
	c.OnError(func(response *colly.Response, err error) {
		fmt.Println(err)
	})

	c.OnRequest(func(r *colly.Request) {
		fmt.Println("Visiting", r.URL)
	})

	err = c.Visit(path)
	if err != nil {
		fmt.Println("error: ", err)
		return l
	}
	return l
}

func parseNode(e *goquery.Selection) *BookDetail {
	b := new(BookDetail)
	aDiv := e.Children()
	// 书籍信息
	attr, exists := aDiv.Attr("href")
	if !exists {
		return nil
	}
	b.Url = "https://" + hostname + attr
	// 图片信息
	imgSrc, _ := aDiv.First().Find("img").Attr("src")
	b.ImgUrl = imgSrc

	// 图书信息
	children := aDiv.Last().Children()
	formatNode := children.First()
	nameNode := formatNode.Next()
	dateNode := nameNode.Next()
	authorNode := dateNode.Next()
	b.Format = strings.TrimSpace(formatNode.Text())
	b.Name = strings.TrimSpace(nameNode.Text())
	b.Date = strings.TrimSpace(dateNode.Text())
	b.Author = strings.TrimSpace(authorNode.Text())
	b.Timestamp = time.Now().Unix()
	return b
}
